package test.sunyu.tools.http;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;

public class ACSigner {

    private static final Logger logger = LoggerFactory.getLogger(Thread.currentThread().getClass());
    private static final String ENCODING = "UTF-8";
    private static final String HASH = "HmacSHA256";

    /**
     * 组装用于签名的完整字符串，必须按照代码中的顺序拼接各个字段。
     *
     * @param developerId 对应公共头域X-Zc-Developer-Id的值
     * @param majorDomain 对应公共头域X-ZC-Major-Domain的值
     * @param subDomain   对应公共头域X-Zc-Sub-Domain的值
     * @param method      请求URL中的method字段的值，而不是HTTP的'GET'等方法
     * @param timestamp   对应公共头域X-Zc-Timestamp的值
     * @param timeout     对应公共头域X-Zc-Timeout的值
     * @param nonce       对应公共头域X-Zc-Nonce的值
     *
     * @return 用于签名的字符串
     */
    public static String genSignString(long developerId,
                                       String majorDomain,
                                       String subDomain,
                                       String method,
                                       long timestamp,
                                       long timeout,
                                       String nonce) {
        String stringToSign = String.valueOf(timeout) + String.valueOf(timestamp) + nonce + String.valueOf(developerId) + method + majorDomain + subDomain;
        return stringToSign;
    }

    /**
     * 通过拼接好的字符串，生成最终的签名字符串
     *
     * @param sk           即Secret Key，登陆平台后获取，注意需要和Access Key配对
     * @param stringToSign 通过genSignString方法生成的用于签名的字符串
     *
     * @return 签名字符串
     */
    public static String genSignature(String sk,
                                      String stringToSign) {
        String signature = "";

        try {
            String encodedSign = URLEncoder.encode(stringToSign, ENCODING);
            try {
                Mac mac = Mac.getInstance(HASH);
                mac.init(new SecretKeySpec(sk.getBytes(ENCODING), HASH));
                byte[] hashData = mac.doFinal(encodedSign.getBytes(ENCODING));

                StringBuilder sb = new StringBuilder(hashData.length * 2);
                for (byte data : hashData) {
                    String hex = Integer.toHexString(data & 0xFF);
                    if (hex.length() == 1) {
                        // append leading zero
                        sb.append("0");
                    }
                    sb.append(hex);
                }
                signature = sb.toString().toLowerCase();
            } catch (Exception e) {
                logger.warn("sha256 exception for[" + sk + "," + stringToSign + "]. e:", e);
            }
        } catch (UnsupportedEncodingException e) {
            logger.warn("encode error, string[" + stringToSign + "] e:" + e);
        }

        return signature;
    }

}
